#ifndef CONFIGFILE_H_INCLUDED
#define CONFIGFILE_H_INCLUDED

#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <fstream>
#include <typeinfo>

template <typename T>
static std::string T_to_string(T const &val)
{
    std::ostringstream ostr;
    ostr << val;

    return ostr.str();
}

template <typename T>
static T string_to_T(std::string const &val)
{
    std::istringstream istr(val);
    T returnVal;
    if (!(istr >> returnVal))
        std::cout << "CFG: Not a valid " << (std::string)typeid (T).name() << " received!\n" << std::endl;

    return returnVal;
}

template <>
std::string string_to_T(std::string const &val)
{
    return val;
}

class Parser
{
    private:
        std::map<std::string, std::string> contents;
        std::string fName;
        //validations functions
        bool startsWith(const char *pre, const char *str) const;
        bool isNumber(std::string const& s) const;
        bool validateRange(int const& typeValue, std::string const& key, std::string const& rangeFrom, std::string const& rangeTo) const;
        bool validateOperMut(const int value, const int otherValue) const;
        //parser functions
        void removeComment(std::string &line) const;
        bool onlyWhitespace(const std::string &line) const;
        bool validLine(const std::string &line) const;
        void extractKey(std::string &key, size_t const &sepPos, const std::string &line) const;
        void extractValue(std::string &value, size_t const &sepPos, const std::string &line) const;
        void extractContents(const std::string &line);
        void parseLine(const std::string &line, size_t const lineNo);
        void ExtractKeys();
    public:
        Parser(const std::string &fName);
        bool keyExists(const std::string &key) const;
        template <typename ValueType>
        ValueType getValueOfKey(const std::string &key, ValueType const &defaultValue = ValueType()) const;
        bool isValidFile() const;
};

template <typename ValueType>
ValueType Parser::getValueOfKey(const std::string &key, ValueType const &defaultValue) const
{
    if (!keyExists(key))
        return defaultValue;

    return string_to_T<ValueType> (contents.find(key)->second);
}

extern Parser Config;

#endif // CONFIGFILE_H_INCLUDED
